package m2acsis.algebre.impl;

import java.util.ArrayList;
import java.util.List;

import m2acsis.algebre.ElemGroupe;
import m2acsis.algebre.helpers.ListHelper;
import m2acsis.algebre.helpers.ToStringHelper;
import m2acsis.algebre.helpers.TypeHelper;

public class Matrice implements ElemGroupe {

	private ElemGroupe[][] coefficients;
	protected int order;
	protected ElemGroupe neutre;
	
	public Matrice(ElemGroupe[][] coefficients) {
		
		if(coefficients == null)
			throw new NullPointerException("parametre null");
		
		if(coefficients.length == 0)
			throw new Error("tableau de longueur nulle");
		
		if(!TypeHelper.isNotNull(coefficients))
			throw new NullPointerException("tableau incomplet");
		
		if(!isSquar(coefficients))
			throw new Error("tableau non carré");
		
		if(!TypeHelper.isSameType(coefficients, coefficients[0][0].getClass()))
			throw new Error("tableau disparate");
		
		this.coefficients = coefficients;
		order = coefficients.length;
		neutre = coefficients[0][0].neutre();
	}
	
	private boolean isSquar(ElemGroupe[][] coefficients){
		
		int lines = coefficients.length;
		
		for(int i = 0; i < lines; i++){
			if(coefficients[i].length != lines)
				return false;
		}
				
		
		return true;
	}

	@Override
	public ElemGroupe neutre() {
		return new Matrice(ListHelper.getArray(getNeutreCoefficient()));
	}
	
	@SuppressWarnings("unchecked")
	protected <T extends ElemGroupe> List<List<T>> getNeutreCoefficient(){
		
		List<List<T>> coefNeutre = new ArrayList<List<T>>();
		
		for(int i = 0; i < order; i++){
			
			List<T> coefLine = new ArrayList<T>();
			for(int j = 0; j < order; j++){
				coefLine.add((T) neutre);
			}
			
			coefNeutre.add(coefLine);
		}
		
		return coefNeutre;
	}

	@Override
	public ElemGroupe oppose() {
		return new Matrice(ListHelper.getArray(getOpposeCoefficents()));
	}
	
	@SuppressWarnings("unchecked")
	protected <T extends ElemGroupe> List<List<T>> getOpposeCoefficents(){
		
		List<List<T>> listReturn = new ArrayList<List<T>>();
		
		for(int i = 0; i < order; i++){
			
			List<T> coefOpp = new ArrayList<T>();
			
			for(int j = 0; j < order; j++){
				
				if(coefficients[i][j].equals(neutre)){
					coefOpp.add((T) coefficients[i][j]);
					continue;
				}
				
				coefOpp.add((T) coefficients[i][j].oppose());
			}
			
			listReturn.add(coefOpp);
		}
		
		return listReturn;
	}

	@Override
	public ElemGroupe somme(ElemGroupe e) {
		
		if(e instanceof Matrice){
			
			Matrice me = (Matrice) e;
			return new Matrice(ListHelper.getArray(getSommeCoefficients(me.coefficients)));
		}
		
		return null;
	}
	
	protected List<List<ElemGroupe>> getSommeCoefficients(ElemGroupe[][] e){
		
		List<List<ElemGroupe>> listReturn = new ArrayList<List<ElemGroupe>>();
		
		for(int i = 0; i < order; i++){
		
			List<ElemGroupe> coefSom = new ArrayList<ElemGroupe>();
			
			for(int j = 0; j < order; j++){
				coefSom.add(coefficients[i][j].somme(e[i][j]));
			}
			
			listReturn.add(coefSom);
		}
		
		return listReturn;
	}
	
	@Override
	public String toString() {
		return ToStringHelper.toString(coefficients, "{", "}");
	}

	
	@Override
	public boolean equals(Object obj) {
		
		if(this == obj){
			return true;
		}
		
		if(obj instanceof Matrice){
			
			Matrice anotherMatrice = (Matrice)obj;
			
			if(order == anotherMatrice.order){
				for(int i = 0; i < order; i++){
					for(int j = 0; j < order; j++)
					if(!coefficients[i][j].equals(anotherMatrice.coefficients[i][j]))
						return false;
				}
				
				return true;
			}
		}
		
		return false;
	}
	
	public int getOrder(){
		return order;
	}
}
